package cn.buk.qms.service;

import cn.buk.common.util.DecimalUtil;
import cn.buk.qms.BillUtil;
import cn.buk.tms.dao.FlightCharterDao;
import cn.buk.tms.dao.ReportDao;
import cn.buk.tms.dto.*;
import cn.buk.tms.entity.misc.*;
import cn.buk.tms.entity.order.flight.FlightRefundOrder;
import cn.buk.tms.entity.order.flight.FlightRefundOrderDetail;
import cn.buk.tms.factory.CustomerDtoFactory;
import cn.buk.common.util.DateUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static cn.buk.common.Constant.DATE_YYYY_MM_DD;
import static java.time.temporal.TemporalAdjusters.*;

/**
 * @author yfdai
 */
@Service
public class ReportServiceImpl extends BaseAbstractService implements ReportService {

    private static final Logger logger = LogManager.getLogger(ReportServiceImpl.class);

    @Autowired
    private ReportDao dao;

    @Autowired
    private FlightCharterDao flightCharterDao;

    /**
     * 销售月报
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<ReportFlightTicketDto> searchFlightMonthlySale(int enterpriseId, int userId, Date beginDate,
                                                               Date endDate, int supplierId, final int customerId) {
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            return doSearchFlightMonthlySale(enterpriseId, beginDate, endDate, supplierId, customerId, allowedCustomerIds);
        }
        return doSearchFlightMonthlySale(enterpriseId, beginDate, endDate, supplierId, customerId, null);
    }



    /**
     * 出票月报，指定op1
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER, RoleInfo.ROLE_OPERATOR})
    public List<ReportFlightTicketDto> searchFlightMonthlySale(int enterpriseId, String username, Date beginDate, Date endDate, int supplierId, int customerId) {
        List<ReportFlightTicketDto> dtos = doSearchFlightMonthlySale(enterpriseId, beginDate, endDate, supplierId, customerId, null);
        // 过滤掉
        return dtos.stream().filter(t -> username.equalsIgnoreCase(t.getOp1())).collect(Collectors.toList());
    }

    /**
     * 搜索月报
     */
    private List<ReportFlightTicketDto> doSearchFlightMonthlySale(int enterpriseId, Date beginDate, Date endDate,
                                                                  int supplierId, int customerId, final List<Integer> allowedCustomerIds) {

        List<ReportFlightTicketDto> tickets = dao.searchFlightTickets(enterpriseId, beginDate, endDate, supplierId);

        if (allowedCustomerIds != null && !allowedCustomerIds.isEmpty()) {
            //只保留allowedCustomerIds里的数据
            tickets = tickets.stream().filter(t -> allowedCustomerIds.contains(t.getCustomerId())).collect(Collectors.toList());
        }

        Map<Integer, Customer> cmap = customerDao.getCustomerSets(enterpriseId);

        List<ReportFlightTicketDto> results = new ArrayList<>();
        for (ReportFlightTicketDto ticket : tickets) {
            BillUtil.processRouteDetail(ticket.getRouteDetail(), ticket.getFlights());

            // 减少数据量
            ticket.setRouteDetail(null);

            if (checkReportDtoCustomerType(ticket, customerId, cmap)) {
                results.add(ticket);
            }
        }

        return results;
    }

    /**
     * 根据退票账单搜索月报
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<ReportFlightRefundDto> searchFlightRefundMonthly(int enterpriseId, int userId, Date beginDate, Date endDate, int supplierId, int customerId) {
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            return doSearchFlightRefundMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, allowedCustomerIds);
        }
        return doSearchFlightRefundMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
    }

    /**
     * 根据退票账单搜索月报 提交人的
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER, RoleInfo.ROLE_OPERATOR})
    public List<ReportFlightRefundDto> searchFlightRefundMonthly(int enterpriseId, String username, Date beginDate, Date endDate, int supplierId, int customerId) {
        List<ReportFlightRefundDto> dtos = doSearchFlightRefundMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
        return dtos.stream().filter(t -> username.equalsIgnoreCase(t.getOp1())).collect(Collectors.toList());
    }

    private List<ReportFlightRefundDto> doSearchFlightRefundMonthly(int enterpriseId, Date beginDate, Date endDate,
                                                                    int supplierId, int customerId, List<Integer> allowedCustomerIds) {

        List<ReportFlightRefundDto> tickets = dao.searchFlightRefunds(enterpriseId, beginDate, endDate);
        if (allowedCustomerIds != null && !allowedCustomerIds.isEmpty()) {
            tickets = tickets.stream().filter(t -> allowedCustomerIds.contains(t.getCustomerId())).collect(Collectors.toList());
        }

        Map<Integer, Customer> cmap = customerDao.getCustomerSets(enterpriseId);

        List<ReportFlightRefundDto> results = new ArrayList<>();
        for (ReportFlightRefundDto ticket : tickets) {
            if (supplierId > 0  && ticket.getSupplier().getId() != supplierId) {
                    continue;

            }

            BillUtil.processRouteDetail(ticket.getRouteDetail(), ticket.getFlights());

            if (checkReportDtoCustomerType(ticket, customerId, cmap)) {
                results.add(ticket);
            }
        }

        return results;
    }

    /**
     * 改签的月报
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<ReportFlightChangeDto> searchFlightChangeMonthly(int enterpriseId, int userId, Date beginDate, Date endDate, int supplierId, int customerId) {
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            return doSearchFlightChangeMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, allowedCustomerIds);
        }
        return doSearchFlightChangeMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
    }

    /**
     * 改签的月报 提交人的
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER, RoleInfo.ROLE_OPERATOR})
    public List<ReportFlightChangeDto> searchFlightChangeMonthly(int enterpriseId, String username, Date beginDate, Date endDate, int supplierId, int customerId) {
        List<ReportFlightChangeDto> dtos = doSearchFlightChangeMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
        return dtos.stream().filter(t -> username.equalsIgnoreCase(t.getOp1())).collect(Collectors.toList());
    }

    private List<ReportFlightChangeDto> doSearchFlightChangeMonthly(int enterpriseId, Date beginDate, Date endDate,
                                                                    int supplierId, int customerId, List<Integer> allowedCustomerIds) {
        List<ReportFlightChangeDto> tickets = dao.searchFlightChanges(enterpriseId, beginDate, endDate);
        if (allowedCustomerIds != null && !allowedCustomerIds.isEmpty()) {
            tickets = tickets.stream().filter(t -> allowedCustomerIds.contains(t.getCustomerId())).collect(Collectors.toList());
        }

        Map<Integer, Customer> cmap = customerDao.getCustomerSets(enterpriseId);

        List<ReportFlightChangeDto> results = new ArrayList<>();
        for (ReportFlightChangeDto ticket : tickets) {
            if (supplierId > 0  && ticket.getSupplier().getId() != supplierId) {
                    continue;

            }

            BillUtil.processRouteDetail(ticket.getRouteDetail(), ticket.getFlights());

            if (checkReportDtoCustomerType(ticket, customerId, cmap)) {
                results.add(ticket);
            }
        }

        return results;
    }

    /**
     * VAS 月报
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<ReportVasDto> searchVasMonthly(int enterpriseId, int userId, Date beginDate, Date endDate, int supplierId, int customerId) {
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            return doSearchVasMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, allowedCustomerIds);
        }
        return doSearchVasMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
    }

    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER, RoleInfo.ROLE_OPERATOR})
    public List<ReportVasDto> searchVasMonthly(int enterpriseId, String username, Date beginDate, Date endDate, int supplierId, int customerId) {
        List<ReportVasDto> dtos = doSearchVasMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
        return dtos.stream().filter(t -> username.equalsIgnoreCase(t.getOp1())).collect(Collectors.toList());
    }

    private List<ReportVasDto> doSearchVasMonthly(int enterpriseId, Date beginDate, Date endDate, int supplierId,
                                                  int customerId, List<Integer> allowedCustomerIds) {
        List<ReportVasDto> tickets = dao.searchVasOrders(enterpriseId, beginDate, endDate);
        if (allowedCustomerIds != null && !allowedCustomerIds.isEmpty()) {
            tickets = tickets.stream().filter(t -> allowedCustomerIds.contains(t.getCustomerId())).collect(Collectors.toList());
        }
        Map<Integer, Customer> cmap = customerDao.getCustomerSets(enterpriseId);

        List<ReportVasDto> results = new ArrayList<>();
        for (ReportVasDto ticket : tickets) {
            if (supplierId > 0 && ticket.getSupplier().getId() != supplierId) {
                    continue;
            }

            if (checkReportDtoCustomerType(ticket, customerId, cmap)) {
                results.add(ticket);
            }
        }
        return results;
    }

    /**
     * 酒店预订月报
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<ReportHotelDto> searchHotelMonthly(int enterpriseId, int userId, Date beginDate, Date endDate, int supplierId, int customerId) {
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            return doSearchHotelMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, allowedCustomerIds);
        }
        return doSearchHotelMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
    }

    /**
     * 酒店预订月报 预订员个人
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER, RoleInfo.ROLE_OPERATOR})
    public List<ReportHotelDto> searchHotelMonthly(int enterpriseId, String username, Date beginDate, Date endDate, int supplierId, int customerId) {
        List<ReportHotelDto> dtos = doSearchHotelMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
        return dtos.stream().filter(t -> username.equalsIgnoreCase(t.getOp1())).collect(Collectors.toList());
    }

    private List<ReportHotelDto> doSearchHotelMonthly(int enterpriseId, Date beginDate, Date endDate, int supplierId,
                                                      int customerId, List<Integer> allowedCustomerIds) {
        List<ReportHotelDto> tickets = dao.searchHotelOrders(enterpriseId, beginDate, endDate);
        if (allowedCustomerIds != null && !allowedCustomerIds.isEmpty()) {
            tickets = tickets.stream().filter(t -> allowedCustomerIds.contains(t.getCustomerId())).collect(Collectors.toList());
        }

        Map<Integer, Customer> cmap = customerDao.getCustomerSets(enterpriseId);

        List<ReportHotelDto> results = new ArrayList<>();
        for (ReportHotelDto ticket : tickets) {
            if (supplierId > 0 && ticket.getSupplier().getId() != supplierId) {
                    continue;

            }

            if (checkReportDtoCustomerType(ticket, customerId, cmap)) {
                results.add(ticket);
            }
        }

        return results;
    }

    /**
     * 火车票月报
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<ReportTrainDto> searchTrainMonthly(int enterpriseId, int userId, Date beginDate, Date endDate, int supplierId, int customerId) {
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            return doSearchTrainMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, allowedCustomerIds);
        }
        return doSearchTrainMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
    }

    /**
     * 火车票月报 预订员个人
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER, RoleInfo.ROLE_OPERATOR})
    public List<ReportTrainDto> searchTrainMonthly(int enterpriseId, String username, Date beginDate, Date endDate, int supplierId, int customerId) {
        List<ReportTrainDto> dtos = doSearchTrainMonthly(enterpriseId, beginDate, endDate, supplierId, customerId, null);
        return dtos.stream().filter(t -> username.equalsIgnoreCase(t.getOp1())).collect(Collectors.toList());
    }

    private List<ReportTrainDto> doSearchTrainMonthly(int enterpriseId, Date beginDate, Date endDate, int supplierId,
                                                      int customerId, List<Integer> allowedCustomerIds) {
        List<ReportTrainDto> results = new ArrayList<>();

        final long start = System.currentTimeMillis();

        List<ReportTrainDto> tickets = dao.searchTrainOrders(enterpriseId, beginDate, endDate);
        if (allowedCustomerIds != null && !allowedCustomerIds.isEmpty()) {
            tickets = tickets.stream().filter(t -> allowedCustomerIds.contains(t.getCustomerId())).collect(Collectors.toList());
        }

        final long end1 = System.currentTimeMillis() - start;

        Map<Integer, Customer> cmap = customerDao.getCustomerSets(enterpriseId);

        for (ReportTrainDto ticket : tickets) {
            if (supplierId > 0 && ticket.getSupplier().getId() != supplierId) {
                continue;
            }

            if (checkReportDtoCustomerType(ticket, customerId, cmap)) {
                results.add(ticket);
            }
        }
        final long end2 = System.currentTimeMillis() - start;
        logger.info("doSearchTrainMonthly: " + end1 + " ms, " + end2 + " ms.");

        return results;
    }

    /**
     * 判断dto的客户类型是否符合条件
     *
     * @param customerId -1： 所有客户；0-仅散客；>0 - 具体某个客户
     */
    private boolean checkReportDtoCustomerType(ReportBaseDto dto, int customerId, Map<Integer, Customer> cmap) {
        if (customerId == 0 && dto.getCustomerType() == 0) {
            // 散客
            return true;
        } else if (customerId == -1) {
            // 全部客户
            if (dto.getCustomerId() > 0) {
                dto.setCustomer(CustomerDtoFactory.createByCustomer(cmap.get(dto.getCustomerId())));
            }

            return true;
        } else {
            if (dto.getCustomerType() == 0) {
                return false;
            }

            if (customerId == dto.getCustomerId()) {
                dto.setCustomer(CustomerDtoFactory.createByCustomer(cmap.get(dto.getCustomerId())));

                return true;
            }

            return false;
        }
    }

    /**
     * 退票月报（根据退票单）
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<FlightRefundOrder> searchMonthlyRefundOrder(int enterpriseId, int userId, Date beginDate, Date endDate, int supplierId) {
        List<FlightRefundOrder> list = refundOrderDao.searchFlightRefundByOrder(enterpriseId, beginDate, endDate, supplierId);
        for (FlightRefundOrder info : list) {
            for (FlightRefundOrderDetail detail : info.getFlights()) {
                detail.setOrder(null);
            }
        }

        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }

            list = list.stream().filter(t -> allowedCustomerIds.contains(t.getCustomerId())).collect(Collectors.toList());
        }


        return list;
    }

    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<ReportStatisticDto> statMonthSale(int enterpriseId, int userId, LocalDate beginDate, LocalDate endDate) {
        List<ReportStatisticDto> list0 = dao.statMonthly(enterpriseId, beginDate, endDate);

        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }

            list0 = list0.stream().filter(t -> allowedCustomerIds.contains(t.getCustomer().getId())).collect(Collectors.toList());
        }

        // 将已支付和未支付的合并到一起
        final int initialSize = list0.size();
        Map<Integer, ReportStatisticDto> map = new HashMap<>(initialSize);

        for (ReportStatisticDto dto : list0) {
            Integer customerId = dto.getCustomer().getId();
            if (map.containsKey(customerId)) {
                ReportStatisticDto dto1 = map.get(customerId);

                dto1.setCount(dto1.getCount() + dto.getCount());

                dto1.setUnpaidTotalAmount(dto1.getUnpaidTotalAmount() + dto.getUnpaidTotalAmount());
                dto1.setUnpaidTotalCost(dto1.getUnpaidTotalCost() + dto.getUnpaidTotalCost());
                dto1.setUnpaidTotalProfit(dto1.getUnpaidTotalProfit() + dto.getUnpaidTotalProfit());

                dto1.setPaidTotalAmount(dto1.getPaidTotalAmount() + dto.getPaidTotalAmount());
                dto1.setPaidTotalCost(dto1.getPaidTotalCost() + dto.getPaidTotalCost());
                dto1.setPaidTotalProfit(dto1.getPaidTotalProfit() + dto.getPaidTotalProfit());

                dto1.setTotalAmount(dto1.getTotalAmount() + dto.getTotalAmount());
                dto1.setTotalCost(dto1.getTotalCost() + dto.getTotalCost());
                dto1.setTotalProfit(dto1.getTotalProfit() + dto.getTotalProfit());
            } else {
                map.put(customerId, dto);
            }
        }

        List<ReportStatisticDto> list1 = new ArrayList<>(map.values());

        list1 = list1.stream()
                .sorted(Comparator.comparing(ReportStatisticDto::getUnpaidTotalAmount).reversed())
                .collect(Collectors.toList());


        return list1;
    }

    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<ReportStatisticDto> statAmountByPaymentMethod(int enterpriseId, int userId, int dateType, Date beginDate, Date endDate) {
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            return dao.statAmountByPaymentMethod(enterpriseId, dateType, beginDate, endDate, allowedCustomerIds);
        } else {
            return dao.statAmountByPaymentMethod(enterpriseId, dateType, beginDate, endDate, null);
        }
    }

    /**
     * 预订员（客服）统计
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER, RoleInfo.ROLE_OPERATOR})
    public List<ReportStatisticDto> statFlightMonthSaleByOp1(final int enterpriseId, final int userId, Date beginDate, Date endDate) {
        List<ReportStatisticDto> list;
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            list = dao.statFlightMonthSaleByOp1(enterpriseId, beginDate, endDate, allowedCustomerIds);
        } else {
            list = dao.statFlightMonthSaleByOp1(enterpriseId, beginDate, endDate, null);
        }


        Set<String> roles = userDao.loadUserRoles(userId);
        if (roles.contains(RoleInfo.ROLE_ADMIN) || roles.contains(RoleInfo.ROLE_CASHIER) || roles.contains(RoleInfo.ROLE_SUPERVISOR)) {
            //可以查看所有
        } else {
            //只能查看自己的
            User user = userDao.getUserById(userId);
            list = list.stream().filter(t -> t.getOp1().equalsIgnoreCase(user.getUsername())).collect(Collectors.toList());
        }

        return list;
    }

    /**
     * 出票员统计
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER, RoleInfo.ROLE_TICKETER})
    public List<ReportStatisticDto> statFlightMonthSaleByOp2(int enterpriseId, final int userId, Date beginDate, Date endDate) {
        List<ReportStatisticDto> list;
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            list = dao.statFlightMonthSaleByOp2(enterpriseId, beginDate, endDate, allowedCustomerIds);
        } else {
            list = dao.statFlightMonthSaleByOp2(enterpriseId, beginDate, endDate, null);
        }

        Set<String> roles = userDao.loadUserRoles(userId);
        if (roles.contains(RoleInfo.ROLE_ADMIN) || roles.contains(RoleInfo.ROLE_CASHIER) || roles.contains(RoleInfo.ROLE_SUPERVISOR)) {
            //可以查看所有
        } else {
            //只能查看自己的
            User user = userDao.getUserById(userId);
            list = list.stream().filter(t -> t.getOp2().equalsIgnoreCase(user.getUsername())).collect(Collectors.toList());
        }

        return list;
    }

    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER})
    public List<ReportStatisticDto> statAmountBySupplier(int enterpriseId, int userId, int dateType, Date beginDate, Date endDate) {
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            return dao.statAmountBySupplier(enterpriseId, dateType, beginDate, endDate, allowedCustomerIds);
        } else {
            return dao.statAmountBySupplier(enterpriseId, dateType, beginDate, endDate, null);
        }
    }

    /**
     * 根据销售员统计
     * 如果是主管角色，则可以查看本分组的所有客服的统计
     */
    @Override
    @Secured({RoleInfo.ROLE_ADMIN, RoleInfo.ROLE_SUPERVISOR, RoleInfo.ROLE_CASHIER, RoleInfo.ROLE_SALE_MAN})
    public List<ReportStatisticDto> statMonthSaleBySalesman(final int enterpriseId, final int userId, Date beginDate, Date endDate) {

        List<ReportStatisticDto> list0 = null;
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }
            list0 = dao.statMonthSaleBySalesman(enterpriseId, beginDate, endDate, allowedCustomerIds);
        } else {
            list0 = dao.statMonthSaleBySalesman(enterpriseId, beginDate, endDate, null);
        }


        Map<String, ReportStatisticDto> map = new HashMap<>();
        for (ReportStatisticDto dto : list0) {
            final String salesman = dto.getSalesman();
            if (map.containsKey(salesman)) {
                ReportStatisticDto dto1 = map.get(salesman);
                dto1.setCount(dto1.getCount() + dto.getCount());
                dto1.setTotalAmount(dto1.getTotalAmount() + dto.getTotalAmount());
                dto1.setTotalCost(dto1.getTotalCost() + dto.getTotalCost());
                dto1.setTotalProfit(dto1.getTotalProfit() + dto.getTotalProfit());
            } else {
                map.put(salesman, dto);
            }

            // 设置二级统计的结果
            ReportStatisticDto dto1 = map.get(salesman);
            dto1.addItemByCustomerName(dto);
        }

        List<ReportStatisticDto> list1 = new ArrayList<>(map.values());
        list1 = list1.stream().sorted(Comparator.comparing(ReportStatisticDto::getCount).reversed()).collect(Collectors.toList());

        //TODO 如果用户只有销售员角色，则只能查看名称相符的统计
        if (userId != enterpriseId) {
            Set<String> roles = userDao.loadUserRoles(userId);
            if (roles.contains(RoleInfo.ROLE_ADMIN)
                    || roles.contains(RoleInfo.ROLE_SUPERVISOR)
                    || roles.contains(RoleInfo.ROLE_CASHIER)) {
                //OK, 不限制
            } else {
                //只能查看自己的
                logger.info("Only see myself sale report.");
                User user = userDao.getUserById(userId);
                final String fullName = user.getEmpname().trim();
                //目前通过全名匹配
                list1 = list1.stream().filter((ReportStatisticDto t) -> fullName.equalsIgnoreCase(t.getSalesman())).collect(Collectors.toList());
            }
        }

        return list1;
    }

    @Override
    public List<ReportStatisticDto> statMonthSaleByAirlines(int enterpriseId, Date beginDate, Date endDate) {
        List<ReportStatisticDto> list0 = dao.statMonthSaleByAirlines(enterpriseId, beginDate, endDate);

        Map<String, ReportStatisticDto> map = new HashMap<>();
        for (ReportStatisticDto dto : list0) {
            final String carrier = dto.getCarrier();
            if (map.containsKey(carrier)) {
                ReportStatisticDto dto1 = map.get(carrier);
                dto1.setCount(dto1.getCount() + dto.getCount());
                dto1.setTotalAmount(dto1.getTotalAmount() + dto.getTotalAmount());
                dto1.setTotalCost(dto1.getTotalCost() + dto.getTotalCost());
                dto1.setTotalProfit(dto1.getTotalProfit() + dto.getTotalProfit());
            } else {
                map.put(carrier, dto);
            }

            // 设置二级统计的结果
            ReportStatisticDto dto1 = map.get(carrier);
            dto1.addItemByCustomerName(dto);
        }

        List<ReportStatisticDto> list1 = new ArrayList<>(map.values());
        list1 = list1.stream().sorted(Comparator.comparing(ReportStatisticDto::getCount).reversed()).collect(Collectors.toList());

        return list1;
    }

    /**
     * 六个月内的，最早日期为2018-1-1的，按月统计未支付金额的，头10名企业客户以及金额发送给管理人员
     */
    @Override
    public void autoAlertMonthlyUnpaidTop10() {
        final LocalDate minDate = LocalDate.of(2018, 1, 1);
        final LocalDate today = LocalDate.now();

        LocalDate baseDate = today.minusDays(180);
        if (baseDate.compareTo(minDate) < 0) {
            baseDate = minDate;
        }

        for (int i = 0; i < 6; i++) {
            LocalDate beginDate = baseDate.with(firstDayOfMonth());
            LocalDate endDate = baseDate.with(lastDayOfMonth());

            if (today.compareTo(endDate) <= 0) {
                break;
            }

            doAutoAlertMonthlyUnpaidTop10(beginDate, endDate);

            baseDate = baseDate.with(firstDayOfNextMonth());
        }
    }

    /**
     * 查询指定日期的TRP数据，统计机票张数和佣金数
     */
    @Override
    public void autoAlertTprStat(final int enterpriseId, final Date sellDate) {
        List<TicketSale> tickets = flightCharterDao.searchTprs(enterpriseId, sellDate);
        int ticketCount = tickets.size();
        int totalCommission = 0;
        for (TicketSale t : tickets) {
            totalCommission += t.getCommission();
        }

        String remark = "(测试)" + DateUtil.formatDate(sellDate, DATE_YYYY_MM_DD) + "出票 " + ticketCount + "张, ";
        remark += "佣金合计 " + totalCommission + ".";

        doSendAlert(enterpriseId, remark, null, EntDepartment.DEPT_ADMINISTRATOR);
    }

    /**
     * 统计一段时间没有业务记录的客户
     */
    @Override
    public void autoAlertNoBusinessCustomer(final int enterpriseId, final int maxDays) {
        if (enterpriseId < 1) {
            return;
        }

        final LocalDate today = LocalDate.now();
        LocalDate baseDate = today.minusDays(maxDays);

        List<ReportStatisticDto> list0 = dao.statBusinessCustomer(enterpriseId, baseDate, today);

        List<Customer> customers = customerDao.getAllCustomers(enterpriseId);


        List<Customer> customers1 = new ArrayList<>();
        for (ReportStatisticDto dto : list0) {
            for (Customer c : customers) {
                if (dto.getCustomer() != null && dto.getCustomer().getId() == c.getId()) {
                    customers1.add(c);
                } else if (c.getCustomerCode() != null && c.getCustomerCode().equalsIgnoreCase(dto.getCustomerCode())) {
                    customers1.add(c);
                }
            }
        }

        customers.removeAll(customers1);

        customers = customers.stream()
                .filter(c -> c.getStatus() == 1)
                .sorted(Comparator.comparing(Customer::getSalesStaff))
                .collect(Collectors.toList());

        //余下的customers中的应该就是没有业务记录的客户
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_YYYY_MM_DD);

        String remark = "以下客户自" + baseDate.format(formatter) + "以来，没有业务记录：\r\n";
        String oldSaleStaff = null; //业务代表

        for (Customer c : customers) {
            if (oldSaleStaff == null) {
                oldSaleStaff = c.getSalesStaff();
                remark += "销售(" + oldSaleStaff + "):\r\n";

            } else if (!oldSaleStaff.equalsIgnoreCase(c.getSalesStaff())) {
                oldSaleStaff = c.getSalesStaff();
                remark += "\r\n";
                remark += "销售(" + oldSaleStaff + "):\r\n";
            }

            remark += c.getVipName() + ", ";

            if (remark.length() > 1000) {
                doSendAlert(enterpriseId, remark, null, EntDepartment.DEPT_ADMINISTRATOR);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                remark = "";
            }
        }


        if (remark != null) {
            remark += ".";
            doSendAlert(enterpriseId, remark, null, EntDepartment.DEPT_ADMINISTRATOR);
        }
    }

    @Override
    public void autoDisableCustomers(final int enterpriseId, final int maxDays, final String username) {
        if (enterpriseId < 1) {
            return;
        }

        final LocalDate today = LocalDate.now();
        LocalDate baseDate = today.minusDays(maxDays);

        List<ReportStatisticDto> list0 = dao.statBusinessCustomer(enterpriseId, baseDate, today);

        List<Customer> customers = customerDao.getAllCustomers(enterpriseId);


        //记录有业务的企业客户, 活跃客户
        List<Customer> activeCustomers = new ArrayList<>();
        for (ReportStatisticDto dto : list0) {
            for (Customer c : customers) {
                if (c.getStatus() == 0) {
                    //该客户已经停用
                    continue;
                }
                if (dto.getCustomer() != null && dto.getCustomer().getId() == c.getId()) {
                    activeCustomers.add(c);
                } else if (c.getCustomerCode() != null && c.getCustomerCode().equalsIgnoreCase(dto.getCustomerCode())) {
                    activeCustomers.add(c);
                }
            }
        }

        //在所有客户中移除活跃客户
        customers.removeAll(activeCustomers);

        //余下的customers中的应该就是没有业务记录的客户
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_YYYY_MM_DD);


        for (Customer c : customers) {
            if (c.getStatus() == 0) {
                //已经停用
                continue;
            }

            //查看该客户的创建日期
            if (c.getCreateTime() == null ||
                    DateUtil.getPastDays(c.getCreateTime()) < maxDays) {
                continue;
            }

            String remark = c.getVipName() + " 自" + baseDate.format(formatter) + "以来没有业务记录，停用。";

            int retCode = customerDao.disableCustomer(enterpriseId, c.getId(), username, remark);

            logger.info(c.getVipName() + ": " + remark);

            if (retCode == 0) {
                doSendAlert(enterpriseId, remark, null, EntDepartment.DEPT_ADMINISTRATOR);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void autoDisableSuppliers(final int enterpriseId, final int maxDays, final String username) {
        if (enterpriseId < 1) {
            return;
        }

        final LocalDate today = LocalDate.now();
        LocalDate baseDate = today.minusDays(maxDays);

        List<ReportStatisticDto> list0 = dao.statAmountBySupplier(enterpriseId, 0, DateUtil.createDate(baseDate), DateUtil.createDate(today), null);

        List<Supplier> suppliers = enterpriseDao.getAllSuppliers(enterpriseId);


        //记录有业务的供应商
        List<Supplier> activeSuppliers = new ArrayList<>();
        for (ReportStatisticDto dto : list0) {
            for (Supplier c : suppliers) {
                if (c.getStatus() == 0) {
                    //该供应商已经停用
                    continue;
                }

                if (dto.getSupplier().getId() == c.getId()) {
                    activeSuppliers.add(c);
                    break;
                }
            }
        }

        //在所有供应商中移除活跃供应商
        suppliers.removeAll(activeSuppliers);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_YYYY_MM_DD);

        for (Supplier c : suppliers) {
            if (c.getStatus() == 0) {
                //已经停用
                continue;
            }

            //查看该供应商的创建日期
            if (c.getCreateTime() == null ||
                    DateUtil.getPastDays(c.getCreateTime()) < maxDays) {
                continue;
            }

            String remark = "供应商(" + c.getName() + ")自" + baseDate.format(formatter) + "以来没有业务记录，暂时停用。";

            int retCode = enterpriseDao.disableSupplier(enterpriseId, c.getId(), username, remark);


            if (retCode == 0) {
                doSendAlert(enterpriseId, remark, null, EntDepartment.DEPT_ADMINISTRATOR);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public List<ReportStatisticDto> statDailySale(int enterpriseId, int userId, LocalDate beginDate,
                                                  LocalDate endDate) {
        List<ReportStatisticDto> list = dao.statDaily(enterpriseId, beginDate, endDate);

        //主管角色只能看到他所属客服组的客户的统计
        if (isOnlySupervisor(userId)) {
            //仅含有“主管”角色
            List<Integer> allowedCustomerIds = searchAllowedCustomerIds(enterpriseId, userId);
            if (allowedCustomerIds.isEmpty()) {
                return new ArrayList<>();
            }

            list = list.stream().filter(t -> allowedCustomerIds.contains(t.getCustomer().getId())).collect(Collectors.toList());
        }

        //按照日期合并
        Map<Date, ReportStatisticDto> map = new HashMap<>(list.size());
        for (ReportStatisticDto dto : list) {
            if (map.containsKey(dto.getOpDate())) {
                ReportStatisticDto dto1 = map.get(dto.getOpDate());

                dto1.setCount(dto1.getCount() + dto.getCount());

                dto1.setTotalAmount(dto1.getTotalAmount() + dto.getTotalAmount());
                dto1.setTotalCost(dto1.getTotalCost() + dto.getTotalCost());
                dto1.setTotalProfit(dto1.getTotalProfit() + dto.getTotalProfit());
            } else {
                map.put(dto.getOpDate(), dto);
            }
        }

        List<ReportStatisticDto> list1 = new ArrayList<>(map.values());

        list1 = list1.stream()
                .sorted(Comparator.comparing(ReportStatisticDto::getOpDate))
                .collect(Collectors.toList());


        return list1;
    }

    private void doAutoAlertMonthlyUnpaidTop10(LocalDate beginDate, LocalDate endDate) {
        //TODO 目前固定统计指定企业
        final int enterpriseId = 5;

        List<ReportStatisticDto> list0 = dao.statMonthly(enterpriseId, beginDate, endDate);

        // 将未支付的合并到一起
        Map<Integer, ReportStatisticDto> map = new HashMap<>();
        for (ReportStatisticDto dto : list0) {
            Integer customerId = dto.getCustomer().getId();
            if (map.containsKey(customerId)) {
                ReportStatisticDto dto1 = map.get(customerId);

                dto1.setUnpaidTotalAmount(dto1.getUnpaidTotalAmount() + dto.getUnpaidTotalAmount());
            } else {
                map.put(customerId, dto);
            }
        }

        List<ReportStatisticDto> list1 = new ArrayList<>(map.values());

        double unpaidTotal = 0;
        for (ReportStatisticDto dto : list1) {
            unpaidTotal += dto.getUnpaidTotalAmount();
        }

        list1 = list1.stream()
                .sorted(Comparator.comparing(ReportStatisticDto::getUnpaidTotalAmount).reversed())
                .filter(t -> t.getUnpaidTotalAmount() > 0)
                .limit(10)
                .collect(Collectors.toList());

        if (list1.isEmpty()) {
            return;
        }

        String remark = beginDate + " 至 " + endDate + "\r\n";
        remark += "未支付总金额为 " + DecimalUtil.keepScale2(unpaidTotal) + "\r\n";
        if (list1.size() > 10) {
            remark += "前 10 为：\r\n";
        } else {
            remark += "依次为：\r\n";
        }
        for (ReportStatisticDto dto : list1) {
            remark += dto.getCustomer().getName() + ": " + dto.getUnpaidTotalAmount() + " \r\n";
        }

        doSendAlert(enterpriseId, remark, null, EntDepartment.DEPT_CASHIER);
    }

}
